home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume25 / utmp < prev    next >
Encoding:
Text File  |  1992-01-10  |  25.5 KB  |  1,094 lines

  1. Newsgroups: comp.sources.unix
  2. From: dws@cs.wisc.edu (DaviD W. Sanderson)
  3. Subject: v25i096: utmp - utility to repair broken /etc/utmp files
  4. Sender: sources-moderator@pa.dec.com
  5. Approved: vixie@pa.dec.com
  6.  
  7. Submitted-By: dws@cs.wisc.edu (DaviD W. Sanderson)
  8. Posting-Number: Volume 25, Issue 96
  9. Archive-Name: utmp
  10.  
  11. I wrote this program to help me repair /etc/utmp files left for
  12. whatever reason with invalid entries.  It works for the utmp file
  13. formats on System V, BSD, AIX3, and AIX 2 (though recently I haven't
  14. had access to an AIX 2 system to make sure it still works there).  I
  15. designed the code to make it easy to add or remove fields for a new
  16. utmp format.
  17.  
  18.     dws@cs.wisc.edu (DaviD W. Sanderson)
  19.  
  20. #! /bin/sh
  21. # This is a shell archive.  Remove anything before this line, then unpack
  22. # it by saving it into a file and typing "sh file".  To overwrite existing
  23. # files, type "sh file -c".  You can also feed this as standard input via
  24. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  25. # will see the following message at the end:
  26. #        "End of shell archive."
  27. # Contents:  README utmp.1 utmp.c Makefile
  28. # Wrapped by dws@skinner on Sat Dec 21 17:06:59 1991
  29. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  30. if test -f 'README' -a "${1}" != "-c" ; then 
  31.   echo shar: Will not clobber existing file \"'README'\"
  32. else
  33. echo shar: Extracting \"'README'\" \(387 characters\)
  34. sed "s/^X//" >'README' <<'END_OF_FILE'
  35. XI wrote this program to help me repair /etc/utmp files left for
  36. Xwhatever reason with invalid entries.  It works for the utmp file
  37. Xformats on System V, BSD, AIX3, and AIX 2 (though recently I haven't
  38. Xhad access to an AIX 2 system to make sure it still works there).  I
  39. Xdesigned the code to make it easy to add or remove fields for a new
  40. Xutmp format.
  41. X
  42. XDaviD W. Sanderson (dws@cs.wisc.edu)
  43. END_OF_FILE
  44. if test 387 -ne `wc -c <'README'`; then
  45.     echo shar: \"'README'\" unpacked with wrong size!
  46. fi
  47. # end of 'README'
  48. fi
  49. if test -f 'utmp.1' -a "${1}" != "-c" ; then 
  50.   echo shar: Will not clobber existing file \"'utmp.1'\"
  51. else
  52. echo shar: Extracting \"'utmp.1'\" \(1727 characters\)
  53. sed "s/^X//" >'utmp.1' <<'END_OF_FILE'
  54. X.\"-------
  55. X.\" $RCSfile: utmp.1,v $$Revision: 1.2 $$Date: 1991/12/21 23:03:43 $
  56. X.\"
  57. X.\" $Log: utmp.1,v $
  58. X.\" Revision 1.2  1991/12/21  23:03:43  dws
  59. X.\" Added caveats.
  60. X.\"
  61. X.\" Revision 1.1  1991/12/21  21:46:38  dws
  62. X.\" Initial revision
  63. X.\"
  64. X.\"-------
  65. X.TH UTMP 1
  66. X.SH NAME
  67. Xutmp \- translate between binary and textual utmp files
  68. X.SH SYNOPSIS
  69. X.B utmp
  70. X.RB [ \-v ]
  71. X.RI [ filename ]
  72. X.SH DESCRIPTION
  73. X.I utmp
  74. Xis useful for fixing a corrupted /etc/utmp file.
  75. XUse
  76. X.I utmp
  77. Xto obtain a printable representation of the file.
  78. XEdit it, and then use
  79. X.I utmp
  80. Xagain to translate it back into binary form.
  81. X.PP
  82. X.I utmp
  83. Xreads from the given file, or stdin if none is given (/etc/utmp
  84. Xif stdin is a tty), and writes to stdout.
  85. XIt detects automatically which transformation to apply.
  86. X.PP
  87. XThe flag
  88. X.B \-v
  89. Xindicates that times are to be printed in a
  90. Xhuman-comprehensible form.
  91. XNote that this output format is not
  92. Xcurrently inverted, so it is not useful for making repairs.
  93. X.PP
  94. XIf
  95. X.I utmp
  96. Xis working correctly then
  97. X.PP
  98. X.in +0.5i
  99. X$ utmp
  100. X.in
  101. X.PP
  102. Xand
  103. X.PP
  104. X.in +0.5i
  105. X$ utmp | utmp | utmp
  106. X.in
  107. X.PP
  108. Xshould produce the same output.
  109. XIdeally
  110. X.PP
  111. X.in +0.5i
  112. X$ utmp | utmp | cmp \- /etc/utmp
  113. X.in
  114. X.PP
  115. Xshould produce no output, but some systems don't fill the entire
  116. Xunused part of the character fields with NULs.
  117. X.SH CAVEATS
  118. XI encourage system administrators to install this command
  119. Xsomewhere besides /etc.
  120. X.PP
  121. XThere are probably /etc/utmp formats I do not yet accomodate.
  122. X.SH FILES
  123. X/etc/utmp
  124. X.br
  125. X/etc/wtmp
  126. X.SH "SEE ALSO"
  127. X.IR who (1),
  128. X(SysV)
  129. X.IR utmp (4),
  130. X(BSD)
  131. X.IR utmp (5)
  132. X.SH AUTHOR
  133. XDaviD W. Sanderson    (dws\|@cs.wisc.edu)
  134. X.SH COPYRIGHT
  135. X\&
  136. X.br
  137. X.if n (C)
  138. X.if t \s+8\v'+2p'\fB\(co\fR\v'-2p'\s0
  139. X\s+2Copyright 1991 by DaviD W. Sanderson\s0
  140. X(but freely redistributable)
  141. END_OF_FILE
  142. if test 1727 -ne `wc -c <'utmp.1'`; then
  143.     echo shar: \"'utmp.1'\" unpacked with wrong size!
  144. fi
  145. # end of 'utmp.1'
  146. fi
  147. if test -f 'utmp.c' -a "${1}" != "-c" ; then 
  148.   echo shar: Will not clobber existing file \"'utmp.c'\"
  149. else
  150. echo shar: Extracting \"'utmp.c'\" \(19486 characters\)
  151. sed "s/^X//" >'utmp.c' <<'END_OF_FILE'
  152. X/*
  153. X * $RCSfile: utmp.c,v $$Revision: 1.2 $$Date: 1991/12/21 22:02:57 $
  154. X *
  155. X * utmp - translate between binary and textual utmp files.
  156. X * 
  157. X * This is useful for fixing a corrupted /etc/utmp.  Use utmp to obtain
  158. X * a printable representation of the file.  Edit it, and then use
  159. X * utmp again to translate it back into binary form.
  160. X * 
  161. X * usage: utmp [-v] [infile]
  162. X * 
  163. X * utmp reads from the given file, or stdin if none is given (/etc/utmp
  164. X * if stdin is a tty), and writes to stdout.  It detects which
  165. X * transformation it is to apply automatically.
  166. X * 
  167. X * The flag -v indicates that times are to be printed in a
  168. X * human-comprehensible form.  Note that this output format is not
  169. X * currently inverted, so it is not useful for making repairs.
  170. X */
  171. X/**
  172. X * If utmp is working correctly then
  173. X *
  174. X *    $ utmp
  175. X * and
  176. X *    $ utmp | utmp | utmp
  177. X *
  178. X * should produce the same output.  Ideally
  179. X *
  180. X *    $ utmp | utmp | cmp - /etc/utmp
  181. X *
  182. X * should produce no output, but some systems don't fill the entire
  183. X * unused part of the character fields with NULs.
  184. X */
  185. X/**
  186. X * The device used to detect what sort of struct utmp we have is
  187. X * to see whether USER_PROCESS (a value for ut_type) is defined by
  188. X * the include files.  If it is, then struct utmp probably looks
  189. X * like this:
  190. X *
  191. X *    struct utmp
  192. X *    {
  193. X *        char    ut_user[8];    User login name
  194. X *        char    ut_id[4];    /etc/inittab id
  195. X *        char    ut_line[12];    device name (console, lnxx)
  196. X *        short    ut_pid;        process id
  197. X *        short    ut_type;    type of entry
  198. X *        struct    exit_status
  199. X *        {
  200. X *        short    e_termination;    Process termination status
  201. X *        short    e_exit;        Process exit status
  202. X *        }    ut_exit;    The exit status of a process
  203. X *                    marked as DEAD_PROCESS.
  204. X *        time_t    ut_time;    time entry was made
  205. X *    };
  206. X *
  207. X * AIX 3 systems have utmp entries like this:
  208. X *
  209. X *    struct utmp
  210. X *    {
  211. X *        char    ut_user[8];    User login name
  212. X *        char    ut_id[14];    /etc/inittab id
  213. X *        char    ut_line[12];    device name (console, lnxx)
  214. X *        short    ut_type;    type of entry
  215. X *        pid_t    ut_pid;        process id
  216. X *        struct exit_status
  217. X *        {
  218. X *        short    e_termination;    Process termination status
  219. X *        short    e_exit;        Process exit status
  220. X *        }    ut_exit;    The exit status of a process
  221. X *                    marked as DEAD_PROCESS.
  222. X *        time_t    ut_time;    time entry was made
  223. X *        char    ut_host[16];    host name
  224. X *    };
  225. X *
  226. X * To use abbreviations of the symbolic ut_type names, compile with
  227. X * SHORT_TYPES defined.
  228. X *
  229. X * If USER_PROCESS is not defined, I assume an archaic struct utmp
  230. X * like this:
  231. X *
  232. X *    struct utmp
  233. X *    {
  234. X *        char    ut_line[8];        tty name
  235. X *        char    ut_name[8];        user id
  236. X *        char    ut_host[16];        host name, if remote
  237. X *        long    ut_time;        time on
  238. X *    };
  239. X *
  240. X * $Log: utmp.c,v $
  241. X * Revision 1.2  1991/12/21  22:02:57  dws
  242. X * Improved the comments.
  243. X *
  244. X * Revision 1.1  1991/12/21  21:44:04  dws
  245. X * Initial revision
  246. X *
  247. X */
  248. X
  249. X#include <sys/types.h>
  250. X#include <assert.h>
  251. X#include <ctype.h>
  252. X#include <time.h>
  253. X#include <stdio.h>
  254. X#include <string.h>
  255. X#include <utmp.h>
  256. X
  257. Xextern void exit();
  258. X
  259. X/*
  260. X * Configuration Section
  261. X * 
  262. X * Configuration is done on a field-by-field basis, for the greatest
  263. X * flexibility (who knows what those vendors will think up next?).
  264. X * 
  265. X * If the symbolic ut_type names are available, assume a SysV-like set
  266. X * of fields.  Otherwise, assume BSD fields.
  267. X * 
  268. X * On some systems, utmp has no ut_id field, and ut_id is #defined to
  269. X * ut_line.
  270. X * 
  271. X * AIX3 systems have the ut_host field.
  272. X */
  273. X
  274. X#ifdef    USER_PROCESS
  275. X# define    HAVE_ut_user
  276. X# ifndef ut_id
  277. X#  define    HAVE_ut_id
  278. X# endif
  279. X# define    HAVE_ut_line
  280. X# define    HAVE_ut_pid
  281. X# define    HAVE_ut_type
  282. X# define    HAVE_ut_exit
  283. X# define    HAVE_ut_time
  284. X# ifdef    _AIX
  285. X#  define    HAVE_ut_host
  286. X# endif
  287. X#else
  288. X# define    HAVE_ut_line
  289. X# define    HAVE_ut_name
  290. X# define    HAVE_ut_host
  291. X# define    HAVE_ut_time
  292. X#endif
  293. X
  294. X#ifndef    UTMP_FILE
  295. X#define    UTMP_FILE    "/etc/utmp"
  296. X#endif
  297. X
  298. X/*
  299. X * getopt() Section
  300. X *
  301. X * The usage() function uses write() instead of printf() so that
  302. X * programs using this template will not necessarily have to use stdio.
  303. X */
  304. X
  305. Xextern int write();
  306. X
  307. X/*
  308. X * swrite() - write() a "string variable" (char *)
  309. X */
  310. X
  311. X#define    swrite(fd, s)    (void) write((fd), (s), strlen(s))
  312. X
  313. X/*
  314. X * lwrite() - write() a "string literal" (char [])
  315. X */
  316. X
  317. X#define    lwrite(fd, lit)    (void) write((fd), (lit), sizeof(lit)-1)
  318. X
  319. X/*
  320. X * basename(s) - assumes the string does not end in '/'
  321. X *
  322. X * This used to be
  323. X *
  324. X * #define basename(s)    (strrchr((s),'/') ? strrchr((s),'/')+1 : (s))
  325. X *
  326. X * but some systems don't have strrchr() and I didn't want to mess
  327. X * with switching between strrchr() and rindex().
  328. X */
  329. X
  330. Xstatic char *
  331. Xbasename(s)
  332. Xchar *s;
  333. X{
  334. X    char *p;
  335. X
  336. X    if (!s || !*s)
  337. X        return s;
  338. X    
  339. X    for(p = s; *s; s++)
  340. X        if(*s == '/')
  341. X            p = s+1;
  342. X    return p;
  343. X}
  344. X
  345. Xstatic char cmdopt[] = "v";
  346. Xstatic char cmdusg[] = " [-v] [filename]\n";
  347. X
  348. Xstatic int flag_v = 0;
  349. X
  350. Xstatic void
  351. Xusage(cmd)
  352. Xchar *cmd;
  353. X{
  354. X    static char prefix[] = "usage: ";
  355. X    char *p = cmd ? basename(cmd) : "a.out";
  356. X    int fd = 2;
  357. X
  358. X    lwrite(fd, prefix);
  359. X    swrite(fd, p);
  360. X    lwrite(fd, cmdusg);
  361. X}
  362. X
  363. X/*
  364. X * cmdline() - return the index of the first non-option argument
  365. X */
  366. Xstatic int
  367. Xcmdline(argc, argv)
  368. Xint argc;
  369. Xchar **argv;
  370. X{
  371. X    extern void     exit();
  372. X    extern char    *optarg; /* points to the option argument */
  373. X    extern int      opterr;    /* when 0, getopt is silent on errors */
  374. X    extern int      optind;    /* argv[optind] is the next argument */
  375. X    extern int      optopt;    /* current option letter */
  376. X
  377. X    int errflag = 0;    /* usage error flag */
  378. X    int errcode = 1;    /* usage error exit code */
  379. X    int c;
  380. X
  381. X    while((c = getopt(argc, argv, cmdopt)) != -1)
  382. X        switch(c)
  383. X        {
  384. X        case 'v':
  385. X            flag_v = 1;
  386. X            break;
  387. X        case '?':
  388. X            errflag = 1;
  389. X            if(optopt == '?')
  390. X                errcode = 0;
  391. X            break;
  392. X        }
  393. X
  394. X    if(errflag)
  395. X    {
  396. X        usage(argv[0]);
  397. X        exit(errcode);
  398. X    }
  399. X
  400. X    return optind;
  401. X}
  402. X
  403. Xextern struct utmp *ud;    /* dummy declaration so I can use sizeof() */
  404. X
  405. X/*
  406. X * LINSIZ is the number of bytes per line of the text representation
  407. X * of a utmp file (including the newline).  The size of such a text
  408. X * file had better be a multiple of LINSIZ.
  409. X */
  410. Xstatic int LINSIZ = 1        /* 1 for the newline */
  411. X
  412. X#ifdef    HAVE_ut_user
  413. X# define nut_user    (sizeof(ud->ut_user)/sizeof(ud->ut_user[0]))
  414. X+            1+nut_user
  415. X#endif
  416. X
  417. X#ifdef    HAVE_ut_id
  418. X# define nut_id        (sizeof(ud->ut_id  )/sizeof(ud->ut_id  [0]))
  419. X+            1+nut_id
  420. X#endif
  421. X
  422. X#ifdef    HAVE_ut_line
  423. X# define nut_line    (sizeof(ud->ut_line)/sizeof(ud->ut_line[0]))
  424. X+            1+nut_line
  425. X#endif
  426. X
  427. X#ifdef    HAVE_ut_pid
  428. X# define nut_pid    5
  429. X+            1+nut_pid
  430. X#endif
  431. X
  432. X#ifdef    HAVE_ut_type
  433. X# if defined(SHORT_TYPES)
  434. X#  define nut_type    4
  435. X# else
  436. X#  define nut_type    10
  437. X# endif
  438. X+            1+nut_type
  439. X#endif
  440. X
  441. X#ifdef    HAVE_ut_exit
  442. X# define nut_exit    17
  443. X+            1+nut_exit
  444. X#endif
  445. X
  446. X#ifdef    HAVE_ut_name
  447. X# define nut_name    (sizeof(ud->ut_name)/sizeof(ud->ut_name[0]))
  448. X+            1+nut_name
  449. X#endif
  450. X
  451. X#ifdef    HAVE_ut_host
  452. X# define nut_host    (sizeof(ud->ut_host)/sizeof(ud->ut_host[0]))
  453. X+            1+nut_host
  454. X#endif
  455. X
  456. X#ifdef    HAVE_ut_time
  457. X# define nut_time    10
  458. X+            nut_time
  459. X#endif
  460. X;            /* End of LINSIZ initialization */
  461. X
  462. X/*
  463. X * VIS_SPC - visible printing character used to represent a space
  464. X * 
  465. X * VIS_TAB - visible printing character used to represent a tab
  466. X * 
  467. X * VIS_NUL - visible printing character used to represent a NUL
  468. X * 
  469. X * The way the i/o translation works, the representation of each field
  470. X * must have no white space.  These visible characters are used to
  471. X * represent the invisible characters.  (Note the inverse mapping
  472. X * will be wrong if the utmp file actually contains any of these
  473. X * characters.)
  474. X * 
  475. X * These characters are not just an artifact of using scanf() to read in
  476. X * each field.  I used visible characters so that the extents and
  477. X * boundaries of the array fields would be clear.
  478. X * 
  479. X * ENVIS() and DEVIS() perform the translations on the given character
  480. X * array.
  481. X */
  482. X
  483. X#define VIS_NUL    '_'
  484. X#define VIS_TAB    '^'
  485. X#define VIS_SPC    '~'
  486. X#define CHR_NUL    0
  487. X#define CHR_TAB    9
  488. X#define CHR_SPC    32
  489. X
  490. X#define ENVIS(str)                        \
  491. X        {                        \
  492. X            int i;                    \
  493. X                                \
  494. X            for(i=0; i<sizeof(str)-1; i++)        \
  495. X            switch((str)[i])            \
  496. X            {                    \
  497. X            case CHR_NUL: (str)[i]=VIS_NUL; break;    \
  498. X            case CHR_TAB: (str)[i]=VIS_TAB; break;    \
  499. X            case CHR_SPC: (str)[i]=VIS_SPC; break;    \
  500. X            }                    \
  501. X        }
  502. X
  503. X#define DEVIS(str)                        \
  504. X        {                        \
  505. X            int i;                    \
  506. X                                \
  507. X            for(i=0; i<sizeof(str)-1; i++)        \
  508. X            switch((str)[i])            \
  509. X            {                    \
  510. X            case VIS_NUL: (str)[i]=CHR_NUL; break;    \
  511. X            case VIS_TAB: (str)[i]=CHR_TAB; break;    \
  512. X            case VIS_SPC: (str)[i]=CHR_SPC; break;    \
  513. X            }                    \
  514. X        }
  515. X
  516. X/*
  517. X * These macros convert the given character args to an integer. (I
  518. X * assume ints are at least 4 bytes long...)
  519. X * 
  520. X * They serve as hash functions, with the useful property that they can
  521. X * be used in case labels when given constants as arguments.
  522. X */
  523. X
  524. X#define char1int(a)        ((unsigned)(a))
  525. X#define char2int(a,b)        ((char1int(a)    <<8) + (char1int(b)))
  526. X#define char3int(a,b,c)        ((char2int(a,b)  <<8) + (char1int(c)))
  527. X#define char4int(a,b,c,d)    ((char3int(a,b,c)<<8) + (char1int(d)))
  528. X
  529. X#ifdef    HAVE_ut_time
  530. X/*
  531. X * cvt_pb_pm() - convert Abbreviated Month name (cftime(3C) field
  532. X * descriptor %b) to Month Number (01 - 12) (cftime(3C) field
  533. X * descriptor %m).
  534. X */
  535. X
  536. Xchar           *
  537. Xcvt_pb_pm(pb)
  538. X    char           *pb;
  539. X{
  540. X    char           *pm = "??";
  541. X
  542. X    switch(char3int(pb[0],pb[1],pb[2]))
  543. X    {
  544. X    case char3int('J','a','n'): pm = "01"; break;
  545. X    case char3int('F','e','b'): pm = "02"; break;
  546. X    case char3int('M','a','r'): pm = "03"; break;
  547. X    case char3int('A','p','r'): pm = "04"; break;
  548. X    case char3int('M','a','y'): pm = "05"; break;
  549. X    case char3int('J','u','n'): pm = "06"; break;
  550. X    case char3int('J','u','l'): pm = "07"; break;
  551. X    case char3int('A','u','g'): pm = "08"; break;
  552. X    case char3int('S','e','p'): pm = "09"; break;
  553. X    case char3int('O','c','t'): pm = "10"; break;
  554. X    case char3int('N','o','v'): pm = "11"; break;
  555. X    case char3int('D','e','c'): pm = "12"; break;
  556. X    }
  557. X    return (pm);
  558. X}
  559. X
  560. X/*
  561. X * utgets_time() - set the ut_time field from the given file
  562. X */
  563. Xutgets_time(f, ut)
  564. X    FILE           *f;
  565. X    struct utmp    *ut;    /* utmp structure to print */
  566. X{
  567. X    (void)fscanf(f,"%ld",        &ut->ut_time);
  568. X}
  569. X
  570. X/*
  571. X * utputs_time() - print the ut_time field to the given file
  572. X *
  573. X * Note that if flag_v is set the output will not be invertible by
  574. X * utgets().
  575. X */
  576. Xutputs_time(f, ut)
  577. X    FILE           *f;
  578. X    struct utmp    *ut;    /* utmp structure to print */
  579. X{
  580. X    char  time[BUFSIZ];
  581. X    int   ntime;
  582. X    char *ptime;
  583. X
  584. X    if(!flag_v)
  585. X    {
  586. X        (void)fprintf(f,"%*ld",    nut_time,    ut->ut_time);
  587. X        return;
  588. X    }
  589. X
  590. X    /* make sure time[] starts out null */
  591. X    for(ptime = time; ptime < time + sizeof time; ptime++)
  592. X        *ptime = '\0';
  593. X#if 0
  594. X    (void)memset(time,0,sizeof(time)/sizeof(time[0]));
  595. X#endif
  596. X
  597. X    /*
  598. X     * Format the time field in a compact, sortable form
  599. X     *
  600. X         * ctime returns a pointer to a 26-character string in the
  601. X     * following form:
  602. X     *
  603. X     *    Sun Sep 16 01:03:52 1973\n\0
  604. X     *    012345678901234567890123 4 5
  605. X     *
  606. X     * I want the time displayed as
  607. X     *
  608. X     *    yy/mm/dd hh:mm:ss
  609. X     *      01234567890123456
  610. X     *
  611. X     * Since cftime is not available everywhere, I will construct
  612. X     * the time myself using the result of ctime().
  613. X     */
  614. X#if 0
  615. X    /* This is how simple it is with cftime() */
  616. X    ntime =    cftime(time, "%y/%m/%d %T", &(ut->ut_time));
  617. X#endif
  618. X
  619. X    ntime = 0;
  620. X    ptime = ctime(&(ut->ut_time));
  621. X
  622. X    strncat(time, ptime + 22, 2); ntime += 2;        /* yy */
  623. X    time[ntime++] = '/';
  624. X    strncat(time, cvt_pb_pm(ptime + 4), 2); ntime += 2;    /* mm */
  625. X    time[ntime++] = '/';
  626. X
  627. X    strncat(time, ptime +  8, 2); ntime += 2;        /* dd */
  628. X    if(time[ntime-2] == ' ')        /* add leading '0' */
  629. X        time[ntime-2] = '0';
  630. X
  631. X    time[ntime++] = ' ';
  632. X    strncat(time, ptime + 11, 8); ntime += 8;      /* hh:mm:ss */
  633. X
  634. X    time[ntime] = '\0';        /* just to be paranoid */
  635. X
  636. X    assert(ntime < (sizeof(time)/sizeof(time[0])) - 1);
  637. X
  638. X    (void)fprintf(f, "%*s",    ntime,        time);
  639. X}
  640. X#endif
  641. X
  642. X/*
  643. X * utgets() - translate a text line from the given file into a struct
  644. X * utmp
  645. X */
  646. Xstruct utmp    *
  647. Xutgets(f)
  648. X    FILE           *f;
  649. X{
  650. X    static struct utmp utb;
  651. X    static struct utmp *ut = &utb;
  652. X
  653. X    if (!f || feof(f))
  654. X        return (struct utmp *) 0;
  655. X
  656. X    /*
  657. X     * Read in the fields
  658. X     */
  659. X#ifdef    HAVE_ut_user
  660. X    {
  661. X        char            user[nut_user + 1];
  662. X
  663. X        (void) fscanf(f, "%s", user);
  664. X        user[nut_user] = '\0';
  665. X        DEVIS(user);
  666. X        (void) strncpy(ut->ut_user, user, nut_user);
  667. X    }
  668. X#endif
  669. X#ifdef    HAVE_ut_id
  670. X    {
  671. X        char            id[nut_id + 1];
  672. X
  673. X        (void) fscanf(f, "%s", id);
  674. X        id[nut_id] = '\0';
  675. X        DEVIS(id);
  676. X        (void) strncpy(ut->ut_id, id, nut_id);
  677. X    }
  678. X#endif
  679. X#ifdef    HAVE_ut_line
  680. X    {
  681. X        char            line[nut_line + 1];
  682. X
  683. X        (void) fscanf(f, "%s", line);
  684. X        line[nut_line] = '\0';
  685. X        DEVIS(line);
  686. X        (void) strncpy(ut->ut_line, line, nut_line);
  687. X    }
  688. X#endif
  689. X#ifdef    HAVE_ut_pid
  690. X    {
  691. X        long    pid;
  692. X    /* (void)fscanf(f,"%hd",        &ut->ut_pid); */
  693. X
  694. X        (void)fscanf(f,"%ld",        &pid);
  695. X        ut->ut_pid = pid;
  696. X    }
  697. X#endif
  698. X#ifdef    HAVE_ut_type
  699. X    {
  700. X    char type[20];
  701. X    short btype = 999;
  702. X
  703. X    (void)fscanf(f,"%s",    type);
  704. X    /* decode the type */
  705. X# if defined(SHORT_TYPES)
  706. X    switch(char4int(type[0],type[1],type[2],type[3]))
  707. X    {
  708. X    case char4int('N','U','L','L'): btype = EMPTY;        break;
  709. X    case char4int('R','L','V','L'): btype = RUN_LVL;    break;
  710. X    case char4int('B','O','O','T'): btype = BOOT_TIME;    break;
  711. X    case char4int('O','L','D','T'): btype = OLD_TIME;    break;
  712. X    case char4int('N','E','W','T'): btype = NEW_TIME;    break;
  713. X    case char4int('I','N','I','P'): btype = INIT_PROCESS;    break;
  714. X    case char4int('L','O','G','P'): btype = LOGIN_PROCESS;    break;
  715. X    case char4int('U','S','R','P'): btype = USER_PROCESS;    break;
  716. X    case char4int('D','E','D','P'): btype = DEAD_PROCESS;    break;
  717. X    case char4int('A','C','C','T'): btype = ACCOUNTING;    break;
  718. X    default:
  719. X        fprintf(stderr, "bad type: %s\n", type);
  720. X    }
  721. X# else
  722. X    switch(char4int(type[0],type[1],type[2],type[3]))
  723. X    {
  724. X    case char4int('E','M','P','T'): btype = EMPTY;        break;
  725. X    case char4int('R','U','N','_'): btype = RUN_LVL;    break;
  726. X    case char4int('B','O','O','T'): btype = BOOT_TIME;    break;
  727. X    case char4int('O','L','D','_'): btype = OLD_TIME;    break;
  728. X    case char4int('N','E','W','_'): btype = NEW_TIME;    break;
  729. X    case char4int('I','N','I','T'): btype = INIT_PROCESS;    break;
  730. X    case char4int('L','O','G','I'): btype = LOGIN_PROCESS;    break;
  731. X    case char4int('U','S','E','R'): btype = USER_PROCESS;    break;
  732. X    case char4int('D','E','A','D'): btype = DEAD_PROCESS;    break;
  733. X    case char4int('A','C','C','O'): btype = ACCOUNTING;    break;
  734. X    default:
  735. X        fprintf(stderr, "bad type: %s\n", type);
  736. X    }
  737. X# endif
  738. X    ut->ut_type = btype;
  739. X    }
  740. X#endif
  741. X#ifdef    HAVE_ut_exit
  742. X    (void)fscanf(f," term=%hd",    &ut->ut_exit.e_termination);
  743. X    (void)fscanf(f," exit=%hd",    &ut->ut_exit.e_exit);
  744. X#endif
  745. X#ifdef    HAVE_ut_name
  746. X    {
  747. X        char            name[nut_name + 1];
  748. X
  749. X        (void) fscanf(f, "%s", name);
  750. X        name[nut_name] = '\0';
  751. X        DEVIS(name);
  752. X        (void) strncpy(ut->ut_name, name, nut_name);
  753. X    }
  754. X#endif
  755. X#ifdef    HAVE_ut_host
  756. X    {
  757. X        char            host[nut_host + 1];
  758. X
  759. X        (void) fscanf(f, "%s", host);
  760. X        host[nut_host] = '\0';
  761. X        DEVIS(host);
  762. X        (void) strncpy(ut->ut_host, host, nut_host);
  763. X    }
  764. X#endif
  765. X#ifdef    HAVE_ut_time
  766. X    utgets_time(f, ut);
  767. X#endif
  768. X
  769. X    (void) fscanf(f, "\n");
  770. X
  771. X    return ut;
  772. X}
  773. X
  774. X/*
  775. X * utputs() - translate from a struct utmp to a text line in the given
  776. X * file
  777. X */
  778. Xutputs(f, ut)
  779. X    FILE           *f;
  780. X    struct utmp    *ut;    /* utmp structure to print */
  781. X{
  782. X    if (!ut || !f)
  783. X        return 0;
  784. X
  785. X    /*
  786. X     * Print out the fields
  787. X     */
  788. X
  789. X#ifdef    HAVE_ut_user
  790. X    {
  791. X        char            user[nut_user + 1];
  792. X
  793. X        (void) strncpy(user, ut->ut_user, nut_user);
  794. X        user[nut_user] = '\0';
  795. X        ENVIS(user);
  796. X        (void) fprintf(f, "%*s ", nut_user, user);
  797. X    }
  798. X#endif
  799. X#ifdef    HAVE_ut_id
  800. X    {
  801. X        char            id[nut_id + 1];
  802. X
  803. X        (void) strncpy(id, ut->ut_id, nut_id);
  804. X        id[nut_id] = '\0';
  805. X        ENVIS(id);
  806. X        (void) fprintf(f, "%*s ", nut_id, id);
  807. X    }
  808. X#endif
  809. X#ifdef    HAVE_ut_line
  810. X    {
  811. X        char            line[nut_line + 1];
  812. X
  813. X        (void) strncpy(line, ut->ut_line, nut_line);
  814. X        line[nut_line] = '\0';
  815. X        ENVIS(line);
  816. X        (void) fprintf(f, "%*s ", nut_line, line);
  817. X    }
  818. X#endif
  819. X#ifdef    HAVE_ut_pid
  820. X    (void)fprintf(f,"%*d ",    nut_pid,    ut->ut_pid);
  821. X#endif
  822. X#ifdef    HAVE_ut_type
  823. X    {
  824. X    char *type;
  825. X
  826. X# if defined(SHORT_TYPES)
  827. X    switch(ut->ut_type)
  828. X    {
  829. X    case EMPTY:        type = "NULL";    break;
  830. X    case RUN_LVL:        type = "RLVL";    break;
  831. X    case BOOT_TIME:        type = "BOOT";    break;
  832. X    case OLD_TIME:        type = "OLDT";    break;
  833. X    case NEW_TIME:        type = "NEWT";    break;
  834. X    case INIT_PROCESS:    type = "INIP";    break;
  835. X    case LOGIN_PROCESS:    type = "LOGP";    break;
  836. X    case USER_PROCESS:    type = "USRP";    break;
  837. X    case DEAD_PROCESS:    type = "DEDP";    break;
  838. X    case ACCOUNTING:    type = "ACCT";    break;
  839. X    default:        type = "unk!";    break;
  840. X    }
  841. X    (void)fprintf(f,"%*s ",    nut_type,    type); /* 5 bytes */
  842. X# else
  843. X    switch(ut->ut_type)
  844. X    {
  845. X    case EMPTY:        type = "EMPTY";        break;
  846. X    case RUN_LVL:        type = "RUN_LVL";    break;
  847. X    case BOOT_TIME:        type = "BOOT_TIME";    break;
  848. X    case OLD_TIME:        type = "OLD_TIME";    break;
  849. X    case NEW_TIME:        type = "NEW_TIME";    break;
  850. X    case INIT_PROCESS:    type = "INIT_PROC";    break;
  851. X    case LOGIN_PROCESS:    type = "LOGIN_PROC";    break;
  852. X    case USER_PROCESS:    type = "USER_PROC";    break;
  853. X    case DEAD_PROCESS:    type = "DEAD_PROC";    break;
  854. X    case ACCOUNTING:    type = "ACCOUNTING";    break;
  855. X    default:        type = "unknown!";    break;
  856. X    }
  857. X    (void)fprintf(f,"%-*s ", nut_type,    type); /* 11 bytes */
  858. X# endif
  859. X    }
  860. X#endif
  861. X#ifdef    HAVE_ut_exit
  862. X    (void)fprintf(f,"term=%*d exit=%*d ",
  863. X        3,
  864. X        ut->ut_exit.e_termination,
  865. X        3,
  866. X        ut->ut_exit.e_exit
  867. X    );
  868. X#endif
  869. X#ifdef    HAVE_ut_name
  870. X    {
  871. X        char            name[nut_name + 1];
  872. X
  873. X        (void) strncpy(name, ut->ut_name, nut_name);
  874. X        name[nut_name] = '\0';
  875. X        ENVIS(name);
  876. X        (void) fprintf(f, "%*s ", nut_name, name);
  877. X    }
  878. X#endif
  879. X#ifdef    HAVE_ut_host
  880. X    {
  881. X        char            host[nut_host + 1];
  882. X
  883. X        (void) strncpy(host, ut->ut_host, nut_host);
  884. X        host[nut_host] = '\0';
  885. X        ENVIS(host);
  886. X        (void) fprintf(f, "%*s ", nut_host, host);
  887. X    }
  888. X#endif
  889. X#ifdef    HAVE_ut_time
  890. X    utputs_time(f, ut);
  891. X#endif
  892. X
  893. X    (void) putc('\n', f);
  894. X
  895. X    return 1;
  896. X}
  897. X
  898. X/*
  899. X * utget() - read a struct utmp from the given file
  900. X */
  901. Xstruct utmp    *
  902. Xutget(f)
  903. X    FILE           *f;
  904. X{
  905. X    static struct utmp utb;
  906. X    static struct utmp *ut = &utb;
  907. X
  908. X    if (fread((char *) ut, sizeof(*ut), 1, f) != 1)
  909. X        return (struct utmp *) 0;
  910. X
  911. X    return ut;
  912. X}
  913. X
  914. X/*
  915. X * utput() - write a struct utmp to the given file
  916. X */
  917. Xutput(f, ut)
  918. X    FILE           *f;
  919. X    struct utmp    *ut;
  920. X{
  921. X    if (!ut || !f)
  922. X        return 0;
  923. X
  924. X    return fwrite((char *) ut, sizeof(*ut), 1, f);
  925. X}
  926. X
  927. X/*
  928. X * docopy() - copy from i to o, translating as appropriate
  929. X */
  930. Xdocopy(i, o)
  931. X    FILE           *i;
  932. X    FILE           *o;
  933. X{
  934. X    FILE           *tmp = tmpfile();
  935. X    int             ilen = 0;    /* size of i file */
  936. X    int             binary = 0;    /* 1 if i file is binary */
  937. X    int             c;
  938. X
  939. X    /*
  940. X     * The textual representation may contain only printing
  941. X     * characters - only the visible characters and space.
  942. X     * 
  943. X     * If there is any character which is not ascii or is not
  944. X     * printable, then treat the file as binary.
  945. X     */
  946. X
  947. X    while ((c = getc(i)) != EOF)
  948. X    {
  949. X        ilen++;
  950. X
  951. X        if (!isascii(c) || !(isprint(c) || c == '\n'))
  952. X        {
  953. X            binary = 1;
  954. X        }
  955. X
  956. X        (void) putc(c, tmp);
  957. X    }
  958. X    if(ilen == 0)
  959. X        return;
  960. X
  961. X    rewind(tmp);
  962. X
  963. X    if (binary)
  964. X    {
  965. X#if 0
  966. X        (void) fprintf(stderr, "Input is Binary\n");
  967. X#endif
  968. X        if (ilen % sizeof(struct utmp))
  969. X        {
  970. X            (void) fprintf(stderr, "Binary wrong size!\n");
  971. X        }
  972. X        while (utputs(o, utget(tmp)))
  973. X            continue;
  974. X    }
  975. X    else
  976. X    {
  977. X#if 0
  978. X        (void) fprintf(stderr, "Input is Text\n");
  979. X#endif
  980. X        if (ilen % LINSIZ)
  981. X        {
  982. X            (void) fprintf(stderr, "Text wrong size!\n");
  983. X        }
  984. X        while (utput(o, utgets(tmp)))
  985. X            continue;
  986. X    }
  987. X}
  988. X
  989. Xmain(ac, av)
  990. X    int             ac;
  991. X    char          **av;
  992. X{
  993. X    FILE           *in = stdin;
  994. X    FILE           *out = stdout;
  995. X    int             optc = cmdline(ac, av);
  996. X
  997. X    ac -= optc;
  998. X    av += optc;
  999. X
  1000. X    switch (ac)
  1001. X    {
  1002. X#if 0
  1003. X    case 2:
  1004. X        if ((out = fopen(av[1], "w")) == (FILE *) 0)
  1005. X        {
  1006. X            exit(1);
  1007. X        }
  1008. X        /* PASSTHROUGH */
  1009. X#endif
  1010. X    case 1:
  1011. X        if ((in = fopen(av[0], "r")) == (FILE *) 0)
  1012. X        {
  1013. X            exit(1);
  1014. X        }
  1015. X        break;
  1016. X    case 0:
  1017. X        if (isatty(0))
  1018. X        {
  1019. X            if ((in = fopen(UTMP_FILE, "r")) == (FILE *) 0)
  1020. X            {
  1021. X                exit(1);
  1022. X            }
  1023. X        }
  1024. X        break;
  1025. X    default:
  1026. X        exit(1);
  1027. X    }
  1028. X
  1029. X    docopy(in, out);
  1030. X
  1031. X    return 0;
  1032. X}
  1033. END_OF_FILE
  1034. if test 19486 -ne `wc -c <'utmp.c'`; then
  1035.     echo shar: \"'utmp.c'\" unpacked with wrong size!
  1036. fi
  1037. # end of 'utmp.c'
  1038. fi
  1039. if test -f 'Makefile' -a "${1}" != "-c" ; then 
  1040.   echo shar: Will not clobber existing file \"'Makefile'\"
  1041. else
  1042. echo shar: Extracting \"'Makefile'\" \(866 characters\)
  1043. sed "s/^X//" >'Makefile' <<'END_OF_FILE'
  1044. X#-------
  1045. X# Installation parameters
  1046. X#-------
  1047. XBINDIR          = $(root)/pub/bin/$(ht)
  1048. XBINMOD          = 500
  1049. XBINOWN          =    dws
  1050. XBINGRP          =    dws
  1051. XMANDIR          = $(root)/pub/man/man1
  1052. XMANMOD          = 400
  1053. XMANOWN          =    dws
  1054. XMANGRP          =    dws
  1055. X
  1056. XLINKER          = $(CC)
  1057. XLDFLAGS          =
  1058. XSHAR          = shar
  1059. X
  1060. XPROG          = utmp
  1061. XPLUG          = README
  1062. XPAGE          = utmp.1
  1063. XTEXT          = Makefile
  1064. XHDRS          =
  1065. XSRCS          = utmp.c
  1066. XOBJS          = utmp.o
  1067. X
  1068. Xall:        $(PROG)
  1069. X
  1070. X$(PROG):    $(OBJS)
  1071. X        $(LINKER) $(LDFLAGS) $(OBJS) -o $(PROG)
  1072. X
  1073. Xclean:;        rm -f $(OBJS)
  1074. X
  1075. Xclobber:    clean
  1076. X        rm -f $(PROG) $(PROG).shar
  1077. X
  1078. Xinstall:    $(PROG) $(PAGE)
  1079. X        install -m $(BINMOD) -o $(BINOWN) -g $(BINGRP) -s $(PROG) $(BINDIR)
  1080. X        install -m $(MANMOD) -o $(MANOWN) -g $(MANGRP) -c $(PAGE) $(MANDIR)
  1081. X
  1082. Xuninstall:;    rm -f $(BINDIR)/$(PROG)
  1083. X        rm -f $(MANDIR)/$(PAGE)
  1084. X
  1085. Xshar:;        $(SHAR) $(PLUG) $(PAGE) $(HDRS) $(SRCS) $(TEXT) > $(PROG).shar
  1086. END_OF_FILE
  1087. if test 866 -ne `wc -c <'Makefile'`; then
  1088.     echo shar: \"'Makefile'\" unpacked with wrong size!
  1089. fi
  1090. # end of 'Makefile'
  1091. fi
  1092. echo shar: End of shell archive.
  1093. exit 0
  1094.